#include "tcpsocketsslimpl.h"
#include "tlswrap.h"

#define GET_REQUEST "GET / HTTP/1.0\r\n\r\n"

int tcpsocketssl_eventcb(ioevstream_t* stream, short err, short what, _sock_t fd)
{
    rc_error(stream != NULL, S_ERROR);
    CTcpSocketSslImpl* tcpsockssl = (CTcpSocketSslImpl*)ioevstream_getctx(stream);
    rc_error(tcpsockssl != NULL, S_ERROR);
    tcpsockssl->OnEventcb(err, what, fd);
    return S_SUCCESS;
}
int tcpsocketssl_readcb(ioevstream_t* stream, short err, buf_ptr ptr, buf_len len)
{
    rc_error(stream != NULL, S_ERROR);
    CTcpSocketSslImpl* tcpsockssl = (CTcpSocketSslImpl*)ioevstream_getctx(stream);
    tcpsockssl->OnReadcb(err, ptr, len);
    return S_SUCCESS;
}
int tcpsocketssl_writecb(ioevstream_t* stream, short err, buf_ptr ptr, buf_len len)
{
    rc_error(stream != NULL, S_ERROR);
    CTcpSocketSslImpl* tcpsockssl = (CTcpSocketSslImpl*)ioevstream_getctx(stream);
    tcpsockssl->OnWritecb(err, ptr, len);
    return S_SUCCESS;
}
CTcpSocketSslImpl::CTcpSocketSslImpl()
{
    m_sock = INVALID_SOCKET;
    m_rstate = SSL_READ_HEAD;
    m_stream = (ioevstream_t*)heap_malloc(sizeof(ioevstream_t));
}
CTcpSocketSslImpl::~CTcpSocketSslImpl()
{
    logi("CTcpSocketSSLImpl::~CTcpSocketSSLImpl");
}
HRESULT CTcpSocketSslImpl::CreateIoOperation(IAsynFrame* pIAsynFrame)
{
    HRESULT hr = S_OK;

    hr = pIAsynFrame->CreateIo(io_operation, (IBase**)&m_pReadOper);
    rc_error(hr == S_OK, E_FAIL);

    hr = pIAsynFrame->CreateIo(io_operation, (IBase**)&m_pWriteOper);
    rc_error(hr == S_OK, E_FAIL);

    hr = pIAsynFrame->CreateIo(io_operation, (IBase**)&m_pConnectOper);
    rc_error(hr == S_OK, E_FAIL);

    return S_OK;
}
HRESULT CTcpSocketSslImpl::BindEvloop(ioevloop_t* loop)
{
    m_evloop = loop;
    ioevstream_init(m_stream, loop, INVALID_SOCKET);
    return S_OK;
}
HRESULT CTcpSocketSslImpl::CloseIo(UINT rw)
{
    return S_OK;
}
HRESULT CTcpSocketSslImpl::BindIo()
{
    rc_error(m_sock != INVALID_SOCKET, E_FAIL);
    return S_OK;
}
HRESULT CTcpSocketSslImpl::OpenIo()
{
    return S_OK;
}
HRESULT CTcpSocketSslImpl::BindEvent(IBase* pSocketEvent)
{
    HRESULT hr = S_OK;

    hr = pSocketEvent->QueryInterface(IID_ISockProc, (void**)&m_pISockProc);
    rc_error(hr == S_OK, E_FAIL);

    return S_OK;
}
HRESULT CTcpSocketSslImpl::UnBindEvent()
{
    m_pISockProc.dispose();
    return S_OK;
}
HRESULT CTcpSocketSslImpl::CreateSock()
{
    HRESULT hr = S_OK;
    m_sock = INVALID_SOCKET;
    m_sock = _createsock(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    rc_error(m_sock != INVALID_SOCKET, E_FAIL);

    set_blocking(m_sock, 1);
    ioevstream_assign(m_stream, m_sock);
    ioevstream_setctx(m_stream, this);
    ioevstream_seteventcb(m_stream, tcpsocketssl_eventcb);
    ioevstream_setreadcb(m_stream, tcpsocketssl_readcb);
    ioevstream_setwritecb(m_stream, tcpsocketssl_writecb);

    return hr;
}
HRESULT CTcpSocketSslImpl::CloseSock()
{
    HRESULT hr = S_OK;

    rc_error(IsOpen() == S_OK, S_OK);
    rc_error(m_sock != INVALID_SOCKET, E_FAIL);
    // TODO: this is error
    _closesock(m_sock);

    m_sock = INVALID_SOCKET;

    return hr;
}
HRESULT CTcpSocketSslImpl::IsOpen()
{
    return S_OK;
}
HRESULT CTcpSocketSslImpl::AttachSock(_sock_t sock)
{
    rc_error(sock != INVALID_SOCKET, E_FAIL);
    m_sock = sock;

    set_blocking(m_sock, 1);
    ioevstream_assign(m_stream, m_sock);
    ioevstream_setctx(m_stream, this);
    ioevstream_seteventcb(m_stream, tcpsocketssl_eventcb);
    ioevstream_setreadcb(m_stream, tcpsocketssl_readcb);
    ioevstream_setwritecb(m_stream, tcpsocketssl_writecb);

    return S_OK;
}
_sock_t CTcpSocketSslImpl::DetachSock()
{
    _sock_t sock;
    sock = m_sock;
    m_sock = INVALID_SOCKET;
    return sock;
}
_sock_t CTcpSocketSslImpl::GetSock()
{
    return m_sock;
}
HRESULT CTcpSocketSslImpl::GetReadOperation(IID id, IBase** pBase)
{
    rc_error(m_pReadOper.m_p != NULL, E_FAIL);
    return this->m_pReadOper->QueryInterface(id, (void**)pBase);
}
HRESULT CTcpSocketSslImpl::GetWriteOperation(IID id, IBase** pBase)
{
    rc_error(m_pWriteOper.m_p != NULL, E_FAIL);
    return this->m_pWriteOper->QueryInterface(id, (void**)pBase);
}
HRESULT CTcpSocketSslImpl::ReadIo(ULONG pos, ULONG size, crtid event, int tm)
{
    return S_OK;
}
HRESULT CTcpSocketSslImpl::WriteIo(ULONG pos, ULONG size, crtid event, int tm)
{
    return S_OK;
}
HRESULT CTcpSocketSslImpl::ConnectIo(NET_ADDR addr, NET_PORT port, crtid cid, int tm)
{
    rc_error(m_sock != INVALID_SOCKET, E_FAIL);
    rc_error(addr != NULL, E_FAIL);
    rc_error(port != INVALID_NET_PORT, E_FAIL);
    rc_error(m_stream.m_p != INVALID_NET_PORT, E_FAIL);

    int rc = S_SUCCESS;

    rc = ioevstream_connectsock(m_stream, addr, port, tm);

    return (rc == S_SUCCESS) ? S_OK : E_FAIL;
}
HRESULT CTcpSocketSslImpl::LoadCertificate(UCHAR* buf, size_t size)
{
    return S_OK;
}
HRESULT CTcpSocketSslImpl::SetSSLCtxAddress(LPCSTR hostname)
{
    rc_error(hostname != NULL, E_FAIL);

    return S_OK;
}
HRESULT CTcpSocketSslImpl::OnEventcb(short err, short what, _sock_t fd)
{
    rc_error(m_pISockProc.m_p != NULL, E_FAIL);

    /*
    if (what == IOEVSTREAM_OPEN) {

        m_session.mbedNetCtx.fd = m_sock;

        int rc = open_handshake(&m_session);

        set_blocking(m_sock, 1);

        int len;
        len = sprintf((char *)m_buffer, GET_REQUEST);
        tls_encrypt_buf(&m_session, m_buffer, len);

        memset(m_sendbuffer, 0, sizeof(m_sendbuffer));

        mbedtls_ssl_context* ssl = &m_session.mbedSslCtx;

        if (ssl->out_left > 0) {
            memcpy(m_sendbuffer, ssl->out_hdr - ssl->out_left, ssl->out_left);
            ioevstream_write(m_stream, m_sendbuffer, ssl->out_left, 30);
        }
    }
     */

    return S_OK;
}
HRESULT CTcpSocketSslImpl::OnReadcb(short err, buf_ptr ptr, buf_len len)
{
    rc_error(m_pISockProc.m_p != NULL, E_FAIL);

    /*

     mbedtls_ssl_context* ssl = &m_session.mbedSslCtx;

    if (m_rstate == SSL_READ_HEAD) {
        memcpy(ssl->in_hdr + ssl->in_left, ptr, len);
        ssl_parse_record_header(ssl);
        m_rstate = SSL_READ_BODY;
        ssl->in_left = ssl->in_msglen;
        ioevstream_read(m_stream, m_recvbuffer, ssl->in_msglen, 30);
        return S_OK;
    }

    if (m_rstate == SSL_READ_BODY) {
        ssl->in_left = 5;
        memcpy(ssl->in_hdr + ssl->in_left, ptr, len);
        ssl_prepare_record_content(ssl);
    }
    */

    return S_OK;
}
HRESULT CTcpSocketSslImpl::OnWritecb(short err, buf_ptr ptr, buf_len len)
{
    rc_error(m_pISockProc.m_p != NULL, E_FAIL);

    ioevstream_read(m_stream, m_recvbuffer, 5, 30);

    /*
        int ret = 0;
        unsigned char buf[1024];
        int size = sizeof(buf) - 1;
        memset(buf, 0, sizeof(buf));
        ret = mbedtls_ssl_read(&m_session.mbedSslCtx, buf, size);
    */

    return S_OK;
}
